-- 월드세팅
Game.Rule.respawnable = false
Game.Rule.enemyfire = true
Game.Rule.friendlyfire = false
Game.Rule.breakable = false

-- 상수
ZOMBIE_ASSIGN_TIME = 20
ROUND_TIME = 100
STATE = {
	READY = 1, -- 라운드 시작 ~ 좀비 스폰 전
	PLAYING = 2, -- 좀비 스폰 후 플레이 중
	END = 3, -- 팀 승리! 다음 라운드 준비 중
}

-- 동기화 변수
scoreHuman = Game.SyncValue:Create('human')
scoreZombie = Game.SyncValue:Create('zombie')
scoreGoal = Game.SyncValue:Create('goal')
scoreHuman.value = 0
scoreZombie.value = 0
scoreGoal.value = 10

-- 접속중인 플레이어 리스트
players = {}
for i = 1, 32 do 
	players[i] = nil
end

-- 라운드 스테이트
state = STATE.READY
roundtimer = Timer:new()

function InitPlayer(player)
	local p
	if player.user.zombie == true then
		print('init zombie : '..player.name)
		p = param.zombie
	else
		print('init human : '..player.name)
		p = param.human
	end

	player.team = p.team
	player.model = p.model
	player.maxhealth = p.hp
	player.health = p.hp
	player.maxarmor = p.armor
	player.armor = p.armor
	player.flinch = p.flinch
	player.knockback = p.knockback
end

function CalcMaxZombie()
	local numPlr = 0
	for i,p in ipairs(players) do
		if p ~= nil then
			numPlr = numPlr + 1
		end
	end

	-- 현재 플레이어 수에 따라 좀비 수 결정
	if numPlr > 20 then
		return 3
	elseif numPlr > 10 then
		return 2
	else
		return 1
	end
end

function AssignZombie()
	-- 랜덤으로 섞인 플레이어 인덱스 배열을 돌면서 필요한 수만큼 좀비 배정
	local list = {}
	for i = 1, 32 do
		list[i] = i
	end
	for i = 1, 32 do
		local n = math.random(1, 32)
		local temp = list[n]
		list[n] = list[i]
		list[i] = temp
	end

	local numZombie = 0
	local maxZombie = CalcMaxZombie()
	for i = 1, 32 do
		local index = list[i]
		if players[index] ~= nil then
			players[index].user.zombie = true
			InitPlayer(players[index])
			numZombie = numZombie + 1
		end

		if numZombie == maxZombie then
			return
		end
	end
end

-- 현재 리스폰 가능한 인간과 좀비 수
function NumAlive()
	local numHuman = 0
	local numZombie = 0
	for i,p in ipairs(players) do
		if p ~= nil and p.user.spawnable == true then
			if p.user.zombie == true then 
				numZombie = numZombie + 1
			else
				numHuman = numHuman + 1
			end
		end
	end

	return numHuman, numZombie
end

function Game.Rule:OnPlayerConnect(player)
	player.user.zombie = false
	player.user.spawnable = true
	players[player.index] = player
	print('connect : ' .. players[player.index].name)
end

function Game.Rule:OnPlayerDisconnect(player)
	print('disconnect : ' .. players[player.index].name)
	players[player.index] = nil
	CheckWinCondition()
end

function Game.Rule:OnPlayerAttack(victim, attacker, damage, weapontype, hitbox)
	if attacker == nil then return end

	-- 준비중엔 무적
	if state ~= STATE.PLAYING then
		return 0
	end

	-- 좀비가 사람 공격
	if (victim.user.zombie == false and attacker.user.zombie == true) then
		print('infect : ' .. victim.name)
		victim.user.zombie = true
		InitPlayer(victim)
		return 0 -- 데미지는 0으로 해서 죽지 않게..
	end
end

function Game.Rule:OnPlayerKilled(victim, killer, weapontype, hitbox)
	-- 좀비가 헤드샷으로 죽으면 부활 불가
	if (victim.user.zombie == true and hitbox == Game.HITBOX.HEAD) then
		victim.user.spawnable = false
	end

	-- 사람이 죽으면 항상 좀비로 부활
	if victim.user.zombie == false then
		victim.user.zombie = true
	end

	if victim.user.spawnable == true then
		victim:Respawn()
	end
end

function Game.Rule:OnPlayerSpawn(player)
	InitPlayer(player)
	if player.user.zombie == false then
		player:ShowBuymenu()
	end
end

function Game.Rule:OnRoundStart()
	--타이머 초기화
	Game.SetTrigger('ShowZombieTimer', false)
	Game.SetTrigger('ShowRoundTimer', false)

	state = STATE.READY
	roundtimer:Start(ZOMBIE_ASSIGN_TIME)
	Game.SetTrigger('ShowZombieTimer', true)

	for i,p in ipairs(players) do
		if p ~= nil then
			p.user.zombie = false
			p.user.spawnable = true
		end
	end
end

function CheckWinCondition(time)
	local numHuman, numZombie = NumAlive()
	local isEnd

	-- 인간 전멸! 좀비 승리
	if numHuman == 0 then
		scoreZombie.value = scoreZombie.value + 1
		isEnd = (scoreZombie.value == scoreGoal.value)
		Game.Rule:Win(Game.TEAM.TR, isEnd)
		state = STATE.END
	-- 좀비 전멸! 인간 승리
	elseif numZombie == 0 then
		scoreHuman.value = scoreHuman.value + 1
		isEnd = (scoreHuman.value == scoreGoal.value)
		Game.Rule:Win(Game.TEAM.CT, isEnd)
		state = STATE.END
	-- 시간 종료! 인간 승리
	elseif roundtimer:IsElapsed() then
		scoreHuman.value = scoreHuman.value + 1
		isEnd = (scoreHuman.value == scoreGoal.value)
		Game.Rule:Win(Game.TEAM.CT, isEnd)
		state = STATE.END
	end
end

function Game.Rule:OnUpdate(time)
	if state == STATE.READY then
		if roundtimer:IsElapsed() then
			AssignZombie()
			state = STATE.PLAYING
			roundtimer:Start(ROUND_TIME)
			Game.SetTrigger('ShowRoundTimer', true)
		end
	elseif state == STATE.PLAYING then
		CheckWinCondition(time)
	end
end